package com.xhtt.common.https;

import net.sf.json.JSONObject;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import javax.net.ssl.*;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ConnectException;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
@Component
@ConfigurationProperties(prefix="lora")
public class HttpClient {
    public static String authorization="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJsb3JhLWFwcC1zZXJ2ZXIiLCJleHAiOjE1MTQzNDE5NzcsImlzcyI6ImxvcmEtYXBwLXNlcnZlciIsIm5iZiI6MTUxNDI1NTU3Nywic3ViIjoidXNlciIsInVzZXJuYW1lIjoibWF4aWlvdCJ9.uQD6Hyuo5zGa__BoX-tRyLrDIACtkZa0anPTczJBrH0";

    private static int flag = 0;


    private static String loraurl;

    private static String username;

    private static String password;

    public  void setLoraurl(String loraurl) {
        HttpClient.loraurl = loraurl;
    }
    public  void setUsername(String username) {
        HttpClient.username = username;
    }
    public  void setPassword(String password) {
        HttpClient.password = password;
    }

    /**
     * 下发指令
     * @param data
     * @return
     */
    public static String downClient(String data,String deviceNum) {

        String url = "https://"+loraurl+"/api/devices/"+deviceNum+"/queue";
        String charset="UTF-8";
        JSONObject json= new JSONObject();
        json.put("confirmed", false);
        json.put("data", data);
        json.put("reference", "rgter3224");
        json.put("fPort", 60);
        System.out.println(data);
        String strResult = "400";
        try {
            strResult  = post(url, json.toString(), charset,authorization);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            return "400";
        } catch (KeyManagementException e) {
            e.printStackTrace();
            return "400";
        } catch (IOException e) {
            e.printStackTrace();
            return "400";
        }
        return strResult;
    }

    /**
     * 登录请求
     * @return
     */
    public static void loginClient() {

        String url = "https://"+loraurl+"/api/internal/login";
        String charset="UTF-8";
        JSONObject test= new JSONObject();
        test.put("username", username);
        test.put("password", password);

        try {
            String strResult = post(url, test.toString(), charset,"");
            JSONObject jsonObject = JSONObject.fromObject(strResult);
            String jwt=jsonObject.getString("jwt");
            authorization = jwt;
            System.out.println(strResult);
            System.out.println("登录成功");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (KeyManagementException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static class TrustAnyTrustManager implements X509TrustManager {
        //该方法检查客户端的证书，若不信任该证书则抛出异常。由于我们不需要对客户端进行认证，因此我们只需要执行默认的信任管理器的这个方法。
        //JSSE中，默认的信任管理器类为TrustManager。
        public void checkClientTrusted(X509Certificate[] chain, String authType)
                throws CertificateException {
        }
        //该方法检查服务器的证书，若不信任该证书同样抛出异常。通过自己实现该方法，可以使之信任我们指定的任何证书。在实现该方法时，也可以简单的不做任何处理，即一个空的函数体，由于不会抛出异常，它就会信任任何证书。
        public void checkServerTrusted(X509Certificate[] chain, String authType)
                throws CertificateException {
        }
        //返回受信任的X509证书数组。
        public X509Certificate[] getAcceptedIssuers() {
            return new X509Certificate[] {};
        }
    }

    private static class TrustAnyHostnameVerifier implements HostnameVerifier {
        public boolean verify(String hostname, SSLSession session) {
            return true;
        }
    }

    /**
     * post方式请求服务器(https协议)
     *
     * @param url
     *            请求地址
     * @param content
     *            参数
     * @param charset
     *            编码
     * @return
     * @throws NoSuchAlgorithmException
     * @throws KeyManagementException
     * @throws IOException
     */
    public static String post(String url, String content, String charset,String author)
            throws NoSuchAlgorithmException, KeyManagementException,
            IOException {
        /*类HttpsURLConnection似乎并没有提供方法设置信任管理器。其实，HttpsURLConnection通过SSLSocket来建立与HTTPS的安全连接，SSLSocket对象是由SSLSocketFactory生成的。
         * HttpsURLConnection提供了方法setSSLSocketFactory(SSLSocketFactory)设置它使用的SSLSocketFactory对象。
         * SSLSocketFactory通过SSLContext对象来获得，在初始化SSLContext对象时，可指定信任管理器对象。
         * */
        SSLContext sc = SSLContext.getInstance("SSL");
        sc.init(null, new TrustManager[] { new TrustAnyTrustManager() },
                new java.security.SecureRandom());

        URL console = new URL(url);
        HttpsURLConnection conn = (HttpsURLConnection) console.openConnection();
        conn.setSSLSocketFactory(sc.getSocketFactory());
        conn.setHostnameVerifier(new TrustAnyHostnameVerifier());
        conn.setDoOutput(true);
        //设置请求头
        conn.setRequestProperty("Content-Type", "application/json;charset=utf-8");
        conn.setRequestProperty("Accept", "application/json");
        if(!"".equals(author)){
            conn.setRequestProperty("Authorization", author);
        }
        conn.connect();
        try {
            conn.connect();
        } catch (ConnectException e) {
            return "400";
        }

        DataOutputStream out = new DataOutputStream(conn.getOutputStream());
        out.write(content.getBytes(charset));
        // 刷新、关闭
        out.flush();
        out.close();
        System.out.println(conn.getResponseCode());
        if(401==conn.getResponseCode() && flag ==0){
            flag = 1;
            HttpClient.loginClient();
           String resultStr =  HttpClient.post(url,content,charset,authorization);
            flag = 0;
            return resultStr;
        }
        if(200 != conn.getResponseCode()){
            return ""+conn.getResponseCode();
        }
        InputStream is = conn.getInputStream();
        if (is != null) {
            ByteArrayOutputStream outStream = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int len = 0;
            while ((len = is.read(buffer)) != -1) {
                outStream.write(buffer, 0, len);
            }
            is.close();
            //判断是否为登录
            if(!"".equals(author)){
                return "200";
            }else{
                return new String(outStream.toByteArray());
            }

        }
        return "200";
    }
}
